package ee.ut.maxorato_macobo.oop.mud.game;

import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;

import ee.ut.maxorato_macobo.oop.mud.items.ContainsItems;
import ee.ut.maxorato_macobo.oop.mud.items.ItemBase;

public class GameRoom implements ContainsItems {
	int roomIndex;
	TreeMap<String, String> exits;
	String roomName;
	String roomDescription;
	String roomExitsString;
	GameArea area;
	ArrayList<PlayerCharacter> playersInRoom;
	ArrayList<NpcCharacter> npcsInRoom;
	ArrayList<ItemBase> itemsInRoom;
	
	public GameRoom(GameArea newArea, int newRoomIndex, String newRoomName, String newRoomDescription, String newRoomExitsString) {
		roomName = newRoomName;
		roomDescription = newRoomDescription;
		roomExitsString = newRoomExitsString;
		
		roomIndex = newRoomIndex;
		area = null;
		
		playersInRoom = new ArrayList<PlayerCharacter>();
		npcsInRoom = new ArrayList<NpcCharacter>();
		itemsInRoom = new ArrayList<ItemBase>();
		
		exits = new TreeMap<String, String>();
		
		if(!roomExitsString.equals("none")) {
			String[] splits = roomExitsString.split(" ");
			
			for(int i = 0; i < splits.length; i++) {
				String[] parts = splits[i].split(",");
				
				if(parts.length != 3) {
					System.err.println("Exit no " + (i+1) + " of room " + getRoomIdent() + " has wrong format.");
					continue;
				}
				else if(exits.containsKey(parts[0])) {
					System.err.println("Exit no " + (i+1) + " of room " + getRoomIdent() + " is a duplicate.");
					continue;
				}
				
				exits.put(parts[0], parts[1] + "," + parts[2]);
			}
		}
		
		area = newArea;
		area.getRoomList().put(getRoomIndex(), this);
	}
	
	public void characterEnteredRoom(GameCharacter character) {
		if(character instanceof PlayerCharacter) {
			playerEnteredRoom((PlayerCharacter)character);
		}
		else if(character instanceof NpcCharacter) {
			npcEnteredRoom((NpcCharacter)character);
		}
	}
	
	public void characterLeftRoom(GameCharacter character, String direction) {
		if(character instanceof PlayerCharacter) {
			playerLeftRoom((PlayerCharacter)character, direction);
		}
		else if(character instanceof NpcCharacter) {
			npcLeftRoom((NpcCharacter)character, direction);
		}
	}
	
	public void playerEnteredRoom(PlayerCharacter player) {
		if(!playersInRoom.contains(player)) {
			playersInRoom.add(player);
			
			ListIterator<PlayerCharacter> it = playersInRoom.listIterator();
			
			while(it.hasNext()) {
				PlayerCharacter nextPlayer = it.next();
				
				if(nextPlayer != player && !nextPlayer.getIsSleeping()) {
					nextPlayer.sendTickMessage("Player " + player.getPlayerName() + " entered the room.");
				}
			}
		}
	}
	
	public void playerLeftRoom(PlayerCharacter player, String direction) {
		if(playersInRoom.contains(player)) {
			playersInRoom.remove(player);
			
			if(direction != null && !direction.equals("void")) {
				ListIterator<PlayerCharacter> it = playersInRoom.listIterator();
				
				while(it.hasNext()) {
					PlayerCharacter nextPlayer = it.next();
					
					if(nextPlayer != player && !nextPlayer.getIsSleeping()) {
						if(direction == null || direction.length() < 1) {
							nextPlayer.sendTickMessage("Player " + player.getPlayerName() + " left the room.");
						}
						else {
							nextPlayer.sendTickMessage("Player " + player.getPlayerName() + " moved " + direction + ".");
						}
					}
				}
			}
		}
	}
	
	public void npcEnteredRoom(NpcCharacter character) {
		if(!npcsInRoom.contains(character)) {
			npcsInRoom.add(character);
			
			ListIterator<PlayerCharacter> it = playersInRoom.listIterator();
			
			while(it.hasNext()) {
				PlayerCharacter nextPlayer = it.next();
				
				if(!nextPlayer.getIsSleeping()) {
					nextPlayer.sendTickMessage(GameUtils.stringCapitalize(character.getTemplate().getNpcDescription()) + " entered the room.");
				}
			}
		}
	}
	
	public void npcLeftRoom(NpcCharacter character, String direction) {
		if(npcsInRoom.contains(character)) {
			npcsInRoom.remove(character);
			
			if(direction != null && !direction.equals("void")) {
				ListIterator<PlayerCharacter> it = playersInRoom.listIterator();
				
				while(it.hasNext()) {
					PlayerCharacter nextPlayer = it.next();
					
					if(!nextPlayer.getIsSleeping()) {
						if(direction == null || direction.length() < 1) {
							nextPlayer.sendTickMessage(GameUtils.stringCapitalize(character.getTemplate().getNpcDescription()) + " has left the room.");
						}
						else {
							nextPlayer.sendTickMessage(GameUtils.stringCapitalize(character.getTemplate().getNpcDescription()) + " moved " + direction + ".");
						}
					}
				}
			}
		}
	}
	
	public PlayerCharacter findPlayerByName(String playerName) {
		Iterator<PlayerCharacter> it = playersInRoom.iterator();
		
		while(it.hasNext()) {
			PlayerCharacter player = it.next();
			
			if(player.getPlayerName().equals(playerName)) {
				return player;
			}
		}
		
		return null;
	}
	
	public NpcCharacter findNpcByName(String npcName) {
		return findNpcByName(npcName, 1);
	}
	
	public NpcCharacter findNpcByName(String npcName, int index) {
		Iterator<NpcCharacter> it = npcsInRoom.iterator();
		int matchCount = 0;
		
		while(it.hasNext()) {
			NpcCharacter npc = it.next();
			
			if(npc.getCharName().equals(npcName)) {
				if(++matchCount == index) {
					return npc;
				}
			}
		}
		
		return null;
	}
	
	public ArrayList<ItemBase> getItemList() {
		return itemsInRoom;
	}
	
	public String canAddItem(ItemBase item) {
		return null;
	}
	
	public void itemAdd(ItemBase item) {
		if(!itemsInRoom.contains(item)) {
			itemsInRoom.add(item);
		}
	}
	
	public void itemRemove(ItemBase item) {
		if(itemsInRoom.contains(item)) {
			itemsInRoom.remove(item);
		}
	}
	
	public ItemBase findItemByName(String itemName) {
		return findItemByName(itemName, 1);
	}
	
	public ItemBase findItemByName(String itemName, int index) {
		ListIterator<ItemBase> it = getItemList().listIterator();
		int matchCount = 0;
		
		while(it.hasNext()) {
			ItemBase item = it.next();
			
			if(item.getName().compareToIgnoreCase(itemName) == 0) {
				
				if(++matchCount == index) {
					return item;
				}
			}
		}
		
		return null;
	}
	
	public ArrayList<PlayerCharacter> getRoomPlayerList() {
		return playersInRoom;
	}
	
	public ArrayList<NpcCharacter> getRoomNpcList() {
		return npcsInRoom;
	}
	
	public void checkExits() {
		for(Map.Entry<String, String> entry : exits.entrySet()) {
			if(GameArea.findRoomByIdent(entry.getValue()) == null) {
				System.err.println("Exit dir '" + entry.getKey() + "' leads to invalid room.");
			}
		}
	}
	
	public String getExitListString() {
		String exitList = "";
		
		for(Map.Entry<String, String> entry : exits.entrySet()) {
			if(GameArea.findRoomByIdent(entry.getValue()) != null) {
				if(exitList.length() > 0) exitList += ", ";
				exitList += entry.getKey();
			}
		}
		
		return exitList;
	}
	
	public ArrayList<String> getExitList() {
		ArrayList<String> exitList = new ArrayList<String>();
		
		for(Map.Entry<String, String> entry : exits.entrySet()) {
			if(GameArea.findRoomByIdent(entry.getValue()) != null) {
				exitList.add(entry.getKey());
			}
		}
		
		return exitList;
	}
	
	public void tellAll(PlayerCharacter exclude, String message) {
		for(PlayerCharacter player : getRoomPlayerList()) {
			if(player != exclude) player.sendTickMessage(message);
		}
	}
	
	public GameRoom getExitAtDir(String dirString) {
		return GameArea.findRoomByIdent(exits.get(dirString));
	}
	
	public String getRoomIdent() {
		return (area != null ? area.getAreaName() : "default") + "," + roomIndex;
	}
	
	public int getRoomIndex() {
		return roomIndex;
	}
	
	public String getRoomName() {
		return roomName;
	}
	
	public String getRoomDesc() {
		return roomDescription;
	}
}
